package com.bot.nft.module.dc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bot.common.chainbo.ChainAccountInfo;
import com.bot.dev.api.DevBlockChainApi;
import com.bot.nft.core.config.LogDescription;
import com.bot.nft.core.enums.chain.ChainLogEnum;
import com.bot.nft.core.enums.dc.NftCertEnum;
import com.bot.nft.core.enums.dc.RedisEnum;
import com.bot.nft.core.util.NftCodeUtil;
import com.bot.nft.module.chain.domain.ChainOptLogInfo;
import com.bot.nft.module.chain.service.ChainOptLogServer;
import com.bot.nft.module.dc.domain.DcNftCert;
import com.bot.nft.module.dc.domain.DcNftInfo;
import com.bot.nft.module.dc.domain.bo.DcNftCertBo;
import com.bot.nft.module.dc.domain.vo.DcNftCertVo;
import com.bot.nft.module.dc.mapper.DcNftCertMapper;
import com.bot.nft.module.dc.mapper.DcNftInfoMapper;
import com.bot.nft.module.dc.service.IDcNftCertService;
import com.bot.nft.module.mb.domain.MbUserInfo;
import com.bot.nft.module.mb.mapper.IMbMemberMapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 藏品证书服务实现类
 * </p>
 *
 * @author zhangkaige
 * @since 2024-01-24
 */
@Service
public class DcNftCertServiceImpl implements IDcNftCertService {


    //藏品证书Mapper
    @Resource
    private DcNftCertMapper nftCertMapper;

    @Resource
    private DcNftInfoMapper dcNftInfoMapper;

    @Resource
    private IMbMemberMapper mbMemberMapper;

    //上链接口
    @Resource
    private DevBlockChainApi devBlockChainApi;

    //操作日志接口
    @Resource
    private ChainOptLogServer optLogServer;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;


    /**
     * 查看藏品证书
     *
     * @param certId 藏品证书标识
     * @return 藏品证书信息
     */
    @Override
    public DcNftCertVo getNftCertVo(String certId) {
        return nftCertMapper.getNftCertVoById(certId);
    }

    @Override
    public Page<DcNftCertVo> pageNftCertVo(Integer pageNo, Integer pageSize, String mbId, String mbPhone,
                                           String nftName, Integer status) {

        //1.创建分页信息
        Page<DcNftCertVo> nftCertVoPage = new Page<>(pageNo, pageSize);
        //2.查询藏品证书信息
        nftCertMapper.pageNftCertVo(nftCertVoPage, mbId, mbPhone, nftName, status);
        return nftCertVoPage;
    }

    /**
     * 转赠藏品证书
     *
     * @param certId     藏品证书标识
     * @param senderId   发送者会员标识
     * @param receiverId 接收者会员标识
     * @return 成功/true，失败/false
     */
    @Override
    public Boolean sendNftCert(String certId, String senderId, String receiverId) {
        boolean flag = true;
        DcNftCert dcNftCert = nftCertMapper.selectById(certId);
        Integer status = dcNftCert.getStatus();
        String holderId = dcNftCert.getMbId();
        //判断用户是否拥有该藏品
        if (!senderId.equals(holderId)) {
            throw new RuntimeException("用户没有此藏品");
        }
        if (status.equals(NftCertEnum.ON_SALE.getValue())) {
            throw new RuntimeException("藏品售卖中");
        }
        if (status.equals(NftCertEnum.TRANSFERRING.getValue())) {
            throw new RuntimeException("藏品转赠中");
        }
        if (status.equals(NftCertEnum.DESTROYED.getValue())) {
            throw new RuntimeException("藏品已销毁");
        }
        //持有中可转赠
        if (status.equals(NftCertEnum.HOLDING.getValue())) {
            //转让藏品证书
            DcNftCert nftCert = new DcNftCert();
            nftCert.setId(dcNftCert.getId());
            nftCert.setStatus(NftCertEnum.TRANSFERRING.getValue());
            int count = nftCertMapper.updateById(nftCert);
            flag = count > 0;
        }

        return flag;
    }


    /**
     * 接收藏品证书
     *
     * @param certId     藏品证书标识
     * @param senderId   发送者会员标识
     * @param receiverId 接收者会员标识
     * @return 成功/true，失败/false
     */
    @Override
    public Boolean receiveNftCert(String certId, String senderId, String receiverId) {
        boolean flag = true;
        DcNftCert dcNftCert = nftCertMapper.selectById(certId);
        Integer status = dcNftCert.getStatus();
        String holderId = dcNftCert.getMbId();
        //判断用户是否拥有该藏品证书
        if (!senderId.equals(holderId)) {
            throw new RuntimeException("藏品数据异常，请稍后重试");
        }
        //判断藏品证书状态
        if (status.equals(NftCertEnum.HOLDING.getValue())) {
            throw new RuntimeException("藏品不可接收");
        }
        if (status.equals(NftCertEnum.ON_SALE.getValue())) {
            throw new RuntimeException("藏品售卖中");
        }

        if (status.equals(NftCertEnum.DESTROYED.getValue())) {
            throw new RuntimeException("藏品已销毁");
        }
        if (status.equals(NftCertEnum.TRANSFERRING.getValue())) {
            DcNftCert nftCert = new DcNftCert();
            nftCert.setId(dcNftCert.getId());
            nftCert.setStatus(NftCertEnum.HOLDING.getValue());
            nftCert.setMbId(receiverId);
            int count = nftCertMapper.updateById(nftCert);
            flag = count > 0;
        }
        return flag;
    }


    /**
     * 挂售藏品证书
     *
     * @param certId 藏品证书标识
     * @param mbId   藏品证书标识
     * @return 成功/true，失败/false
     */
    @Override
    public Boolean sellNftCert(String certId, String mbId) {
        boolean flag = true;
        DcNftCert dcNftCert = nftCertMapper.selectById(certId);
        Integer status = dcNftCert.getStatus();
        String holderId = dcNftCert.getMbId();
        //判断用户是否拥有该藏品
        if (!mbId.equals(holderId)) {
            throw new RuntimeException("用户没有此藏品");
        }
        //判断藏品证书状态
        if (status.equals(NftCertEnum.ON_SALE.getValue())) {
            throw new RuntimeException("藏品售卖中");

        }
        if (status.equals(NftCertEnum.TRANSFERRING.getValue())) {
            throw new RuntimeException("藏品转赠中");
        }
        if (status.equals(NftCertEnum.DESTROYED.getValue())) {
            throw new RuntimeException("藏品已销毁");
        }
        if (status.equals(NftCertEnum.HOLDING.getValue())) {
            DcNftCert nftCert = new DcNftCert();
            nftCert.setId(dcNftCert.getId());
            nftCert.setStatus(NftCertEnum.ON_SALE.getValue());
            int count = nftCertMapper.updateById(nftCert);
            flag = count > 0;
        }
        return flag;
    }

    /**
     * 发布藏品证书
     *
     * @param nftId   藏品标识
     * @param mbId    持有会员标识
     * @param busType 业务类型
     * @return 成功/true，失败/false
     */
    @Override
    public DcNftCert genCert(String nftId, String mbId, Integer busType) {
        DcNftInfo nftInfo = dcNftInfoMapper.selectById(nftId);
        MbUserInfo mbUserInfo = mbMemberMapper.selectById(mbId);
        //生成藏品证书编号
        Integer code = (Integer) redisTemplate.boundListOps(RedisEnum.KEY.getValue() + nftId).rightPop();
        //藏品证书名称
        String certName = nftInfo.getName() + "#" + code;
        //藏品证书标识
        String certId = IdUtil.getSnowflakeNextIdStr();
        //发行藏品
        ChainAccountInfo chainInfo = new ChainAccountInfo();
        chainInfo.setName(certName);
        chainInfo.setUri(nftInfo.getCover());
        chainInfo.setClassId(nftInfo.getContract());
        chainInfo.setType(nftInfo.getType());
        chainInfo.setSaleTime(nftInfo.getSaleTime());
        chainInfo.setNativeAddress(mbUserInfo.getNativeAddress());
        chainInfo.setCode(String.valueOf(code));
        //藏品证书上链
        String optionId = devBlockChainApi.publishNft(chainInfo);
        //操作日志
        ChainOptLogInfo optLogInfo = new ChainOptLogInfo();
        optLogInfo.setStatus(ChainLogEnum.UNTREATEDSTATUS.getValue());
        optLogInfo.setDcOptType(busType);
        optLogInfo.setChainOptType(ChainLogEnum.CHAIN_PUBLISH_NFT.getValue());
        optLogInfo.setObjId(certId);
        optLogInfo.setOperationId(optionId);
        optLogInfo.setOptTime(new Date());
        optLogInfo.setUserId(mbId);
        String remark = "";
        if (busType.equals(ChainLogEnum.BUSINESS_PURCHASE.getValue())) {
            remark = ChainLogEnum.BUSINESS_PURCHASE.getName();
        }
        if (busType.equals(ChainLogEnum.BUSINESS_AIRDROP.getValue())) {
            remark = ChainLogEnum.BUSINESS_AIRDROP.getName();
        }
        if (busType.equals(ChainLogEnum.BUSINESS_SYN.getValue())) {
            remark = ChainLogEnum.BUSINESS_SYN.getName();
        }
        if (busType.equals(ChainLogEnum.BUSINESS_DRAW.getValue())) {
            remark = ChainLogEnum.BUSINESS_PURCHASE.getName();
        }
        optLogInfo.setOptDesc(LogDescription.issuance(mbId, certId, remark));
        //保存操作日志
        Boolean flag = optLogServer.insertCPLog(optLogInfo);

        //封装藏品证书信息
        DcNftCert dcNftCert = new DcNftCert();
        dcNftCert.setId(certId);
        dcNftCert.setNftId(nftId);
        dcNftCert.setName(certName);
        dcNftCert.setCode(111);
        dcNftCert.setUnit(NftCertEnum.CHAIN_UNIT.getName());
        dcNftCert.setStatus(NftCertEnum.HOLDING.getValue());
        dcNftCert.setReleaseTime(new Date());

        return dcNftCert;
    }

    @Override
    public Boolean transferCert(String certId, String mbId, Integer busType) {
        DcNftCert certInfo = nftCertMapper.selectById(certId);
        DcNftInfo nftInfo = dcNftInfoMapper.selectById(certInfo.getNftId());
        MbUserInfo recUser = mbMemberMapper.selectById(mbId);
        MbUserInfo sendUser = mbMemberMapper.selectById(certInfo.getMbId());
        //转让藏品证书
        String optionId = devBlockChainApi.makeOverNft(nftInfo.getContract(), certInfo.getChainAddr(),
                sendUser.getNativeAddress(), recUser.getNativeAddress());
        //操作日志
        ChainOptLogInfo optLogInfo = new ChainOptLogInfo();
        optLogInfo.setStatus(ChainLogEnum.UNTREATEDSTATUS.getValue());
        optLogInfo.setDcOptType(busType);
        optLogInfo.setChainOptType(ChainLogEnum.CHAIN_MAKE_OVER_NFT.getValue());
        optLogInfo.setObjId(certId);
        optLogInfo.setOperationId(optionId);
        optLogInfo.setOptTime(new Date());
        optLogInfo.setUserId(mbId);
        String remark = "";
        if (busType.equals(ChainLogEnum.BUSINESS_MARKET_PURCHASE.getValue())) {
            remark = ChainLogEnum.BUSINESS_MARKET_PURCHASE.getName();
        }
        if (busType.equals(ChainLogEnum.BUSINESS_TRANSFER.getValue())) {
            remark = ChainLogEnum.BUSINESS_TRANSFER.getName();
        }
        optLogInfo.setOptDesc(LogDescription.issuance(mbId, certId, remark));
        //保存操作日志
        return optLogServer.insertCPLog(optLogInfo);
    }

    @Override
    public Boolean updateCert(DcNftCertBo dcNftCertBo) {
        DcNftCert nftCert = BeanUtil.copyProperties(dcNftCertBo, DcNftCert.class);
        int count = nftCertMapper.updateById(nftCert);
        return count > 0;
    }


}
